package com.rcmd.client;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import org.apache.log4j.Logger;

import com.rcmd.agent.Proc;
import com.rcmd.cmd.CMDCommand;
import com.rcmd.cmd.Command;
import com.rcmd.cmd.DataCommand;
import com.rcmd.cmd.ErrorCommand;
import com.rcmd.cmd.FileCommand;
import com.rcmd.cmd.FileCommand.ACTION;
import com.rcmd.cmd.FileDataCommand;
import com.rcmd.cmd.FileIO;
import com.rcmd.cmd.InitCommand;
import com.rcmd.cmd.WireIO;

public class Client {
    ObjectInput sock_in ; 
    ObjectOutput sock_out  ;
    PrintWriter cmd_out ;
    BufferedReader cmd_in ;
    Thread input_Thread ;
    Socket s ;
    Logger log ;
    public Client(String host, int port) throws IOException{
    	s= new Socket(host, port) ;
    	sock_out = new ObjectOutputStream(s.getOutputStream());
    	sock_in= new ObjectInputStream(s.getInputStream()) ;
    	cmd_out = new PrintWriter(System.out);
    	cmd_in = new BufferedReader(new InputStreamReader(System.in) );
    	input_Thread = new Thread(new ClientProc(sock_in));
    	log = Logger.getLogger(s.getPort()+"");
        log.addAppender(util.Log4jUtil.getFileAppender("client-"+String.valueOf(s.getPort())+".log"));

    }
    public void connect() throws IOException, InterruptedException {
    	createProcess();

    	input_Thread.start() ;
		String cmd = "" ; 
		while (! cmd.equals("Q!")) {
			cmd = cmd_in.readLine();
			debugPrint("++++++++++++++ "+ cmd +" +++++++++++++++++");
			debugPrint("");
			handlerCmd(cmd);
		}
		CMDCommand rcmd = new CMDCommand("q!");
		WireIO.write(sock_out, rcmd);
		clean();
	}
    public void handlerCmd(String cmds) throws IOException, InterruptedException{
    	String []args = cmds.split("\\ +") ;
    	String cmd=args[0] ;
    	if(cmd.equals("get-file")){
    		get_file(args) ;
    	}else if(cmd.equals("put-file")){
    		put_file(args) ;
    	}
    	else{
    		CMDCommand rcmd = new CMDCommand(cmds);
			WireIO.write(sock_out, rcmd);
    	}
    }
    public void createProcess() throws IOException{
    	System.out.print("please input the cmd shell you want to use( cmd/bash/ruby....):");
    	String cmd = cmd_in.readLine();
    	init_server(cmd) ;
    }
    public void init_server(String...args) throws IOException{
    	String cmd = args[0] ;
    	InitCommand init = new InitCommand(cmd) ;
    	WireIO.write(sock_out, init) ;
    }
    public void get_file(String...args) throws IOException, InterruptedException{
//    	input_Thread.wait();
//    	input_Thread.yield();
    	String remoteFile = args[1] ;
    	String localFile = args[2];
    	FileCommand fdata = new FileCommand();
    	fdata.setFileServer(remoteFile) ;
    	fdata.setFileClient(localFile) ;
    	fdata.setAction(ACTION.GET) ;
    	WireIO.write(sock_out, fdata) ;
    
    	
//    	input_Thread.interrupt();
    }
    public void put_file(String...args) throws IOException{
    	String localFile = args[1];
    	String remoteFile = args[2] ;
    	FileCommand fdata = new FileCommand();
    	fdata.setFileServer(localFile) ;
    	fdata.setFileClient(remoteFile) ;
    	fdata.setAction(ACTION.GET) ;

    	FileIO.writeFile2Pipe(fdata, sock_out,log) ;
    }
    protected void clean(){
		try {
			if( sock_in!=null){
				sock_in.close();
				debugPrint("close socket input stream");
			}
			if( sock_out!=null){
				sock_out.close();
				debugPrint("close socket output stream");
			}
			s.close() ;
			
		} catch (IOException e) {
			debugPrint(e) ;
		}
		debugPrint("resource is clean!") ;
	}
	public static void main(String[] args) throws UnknownHostException,
			IOException, InterruptedException {
		String host ;
		int port = 1212 ;
		BufferedReader cmd_in = new BufferedReader(new InputStreamReader(System.in) );
		if( args.length == 0){
			System.out.print("please input the host: ");
			host = cmd_in.readLine() ;
			System.out.print("please input the port: ");
			port = Integer.parseInt(cmd_in.readLine() );
		}
		else{
			host = args[0] ;
			port= Integer.parseInt(args[1]) ;
		}
		Client c = new Client(host, port ) ;
		System.out.println(">>>"+ host+":"+port+">>>") ;
		c.connect() ;
		System.out.println("bye") ;
	}
	public void debugPrint(String s){
        //System.out.println("debug: " + s) ;
        log.info(s) ;
    }
    public void debugPrint(Throwable  s){
        //System.out.println("debug: " + s.getMessage()) ;
        log.error(s.getMessage(),s) ;
        //s.printStackTrace(System.out) ;
    }

		
	class ClientProc implements Runnable {
	ObjectInput inputStream = null;
	String name;
	public ClientProc(ObjectInput inputStream) {
		this.inputStream = inputStream;
	}
	@Override
	public void run() {
		try {
			while (true) {
				Command cmd = WireIO.read(inputStream);
				switch (cmd.getType()) {
				case Command.DATA:
					String cmddata = new String(((DataCommand) cmd).getData());
					debugPrint(cmddata);
					break;
				case Command.FILEDATA:
					FileDataCommand fcmd = (FileDataCommand)cmd ;
					FileIO.readFileFromPipe(fcmd, inputStream, log) ;
					break;
				case Command.ERROR:
					ErrorCommand err=(ErrorCommand)cmd;
					debugPrint(err.getCause());
					break ;
				default:
					System.out.println("get wrong cmd");	
				break;
				}
			}
		} catch (IOException e) {
			//e.printStackTrace();
		}
	}
}
}
